#include "Fraction.h"
//Implementation of methods in Fraction class
namespace SymCe{

	Fraction::Fraction(){
		p=1;
		q=1;
		sign = POSITIVE;
	}
	Fraction::Fraction(const Fraction & fraction){
		sign = fraction.sign;
		p = fraction.p;
		q = fraction.q;
	}
	
	
	Fraction::Fraction(Sign sign_, Integer p_, Integer q_){
		if (p_ == 0){
			sign = POSITIVE;
		}else{
			sign=sign_;
		}
		p=p_;
		q=q_;
		reduce();
	}
	Fraction::Fraction(int p_, int q_){
		//Find signum of both p_ and q_. Store it in "two bit bitmask".
		int sg = (p_ < 0) ? 1 : 0;
		sg += (q_< 0) ? 2 : 0;
		switch(sg){
			case 0: //00
				sign = POSITIVE;
				p = p_;
				q = q_;
				break;
			case 1: //01
				sign = NEGATIVE;
				p = -p_;
				q = q_;
				break;
			case 2: //10
				sign = NEGATIVE;
				p = p_;
				q = -q_;
				break;
			case 3: //11
				sign = POSITIVE;
				p = -p_;
				q = -q_;
		}
		if (p_ == 0){
			sign = POSITIVE;
		}
		reduce();
	}
	Fraction::Fraction(int i_){
		if (i_ >= 0){
			p = i_;
			sign = POSITIVE;
		}else{
			p = -i_;
			sign = NEGATIVE;
		}
		q = 1;
	}

	Fraction::~Fraction(){}

	Fraction Fraction::opposite(void) const{
		return Fraction(other(sign), p, q);
	}

	Fraction Fraction::inverted(void) const{
		return Fraction(sign, q, p);
	}

	void Fraction::reduce(void){
		Integer d = gcd(p, q);
		p = p/d;
		q = q/d;
	}
		
	Fraction Fraction::operator-(void) const{
		if (p!=0){
			return Fraction(other(sign), p, q);
		}else{
			return Fraction(POSITIVE, 0, 1);
		}
	}

	Fraction Fraction::operator+(void) const{
		return Fraction(*this);
	}
	
	Fraction Fraction::operator +(const Fraction & fraction) const{
		//Find common denominator, (convert both fractions to that denominator - just store that as numbers),
		//add them (watch out the signs) and then reduce the result (and fractions)
		Integer common_denominator = lcm(q, fraction.q); 
		Integer first_numerator = p*common_denominator/q;	//common_denominator/q is factor to multiply the numerator;
		Integer second_numerator = fraction.p*common_denominator/fraction.q;
		Integer new_numerator;
		Sign new_sign;
		if (sign == fraction.sign){
			new_sign = sign;
			new_numerator = first_numerator + second_numerator;
		}else{
			if(first_numerator > second_numerator){
				new_sign = sign;
				new_numerator = first_numerator - second_numerator;
			}else{
				new_sign = fraction.sign;
				new_numerator = second_numerator - first_numerator;
			}
		}
		//We can reduce now, but constructor should take care of that for us.
		return Fraction(new_sign, new_numerator, common_denominator);
	}

	Fraction Fraction::operator-(const Fraction & fraction) const{
		//Subtracting a number is adding the opposite one.
		return *this + fraction.opposite();
	}

	Fraction Fraction::operator*(const Fraction & fraction) const{
		//Multiply numerators, multiply denominators, determine sign and return new fraction (constructor will reduce it);
		//TODO: It can overflow and it does not have to, if we try to reduce what possible before multiplying.
		Integer new_numerator = p * fraction.p;
		Integer new_denominator = q * fraction.q;
		Sign new_sign = (sign == fraction.sign ? POSITIVE : NEGATIVE);
		return Fraction(new_sign, new_numerator, new_denominator);
	}

	Fraction Fraction::operator/(const Fraction & fraction) const{
		//Multiply with inverse.
		return (*this) * fraction.inverted();
	}

	Fraction & Fraction::operator=(const Fraction & fraction){
		if (this != &fraction){
			p = fraction.p;
			q = fraction.q;
			sign = fraction.sign;
		}
		return * this;
	}

	bool Fraction::operator<(const Fraction & fraction) const{
		if (sign != fraction.sign){
			return sign == NEGATIVE; //One is positive, second is negative. If first is negative, it is smaller.
		}
		//otherwise - same denominator...
		Integer d = lcm(q, fraction.q);
		Integer first = p*d/q;
		Integer second = fraction.p*d/fraction.q;
		return sign == POSITIVE ? first < second : second < first;
	}

	//All other operators can be constructed with operator<, however I will write also operator== fully (it is simple)
	bool Fraction::operator==(const Fraction & fraction) const{
		return ((p == fraction.p) && (q == fraction.q) && (sign == fraction.sign)); //in any order
	}

	bool Fraction::operator<=(const Fraction & fraction) const{
		return ((*this < fraction) || (*this == fraction));
	}

	bool Fraction::operator!=(const Fraction & fraction) const{
		return !(*this == fraction);
	}

	bool Fraction::operator>(const Fraction & fraction) const{
		return fraction < *this;
	}

	bool Fraction::operator>=(const Fraction & fraction) const{
		return fraction <= *this;
	}

	bool Fraction::is_negative(void) const{
		return sign == NEGATIVE;
	}

	bool Fraction::is_positive(void) const{
		return sign == POSITIVE;
	}

	Integer Fraction::get_numerator(void) const{
		return p;
	}

	Integer Fraction::get_denominator(void) const{
		return q;
	}
	std::ostream & operator<<(std::ostream & s, const Fraction & fraction){
		Integer num = fraction.get_numerator();
		Integer den = fraction.get_denominator();
		s << '(';
		if(den != 1){
			if(fraction.is_negative()){
				s << '-' << num << '/' << den;
			}else{
				s << num << '/' << den;
			}
		}else{
			if(fraction.is_negative()){
				s << '-' << num;
			}else{
				s << num;
			}
		}
		s << ')';
		return s;
	}

}

